﻿// ---------------------------------------------------------------------------------------------------------------------
//   Copyright (c) SRT Solutions 2009. All rights reserved.
// ---------------------------------------------------------------------------------------------------------------------

namespace SRTSolutions.Elevate
{
    using global::System;
    using global::System.Net;

    /// <summary>
    /// This class contains extension methods on string
    /// that implement TryParse to return nullable types
    /// on the requested type.
    /// </summary>
    /// <remarks>
    /// These methods levrage the underlying TryParse methods 
    /// to parse the strings as value types, and return those 
    /// types as a nullable. The null value would indicate a 
    /// failure to parse the type from the string. Otherwise,
    /// the value is returned.
    /// </remarks>
    public static class TryParseExtension
    {
        /// <summary>
        /// Tries to parse a string as a bool, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>true, or false, based on input. null if parsing fails</returns>
        public static bool? TryParseBool(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            bool result;
            return bool.TryParse(value, out result) ? result : default(bool?);
        }

        /// <summary>
        /// Tries to parse a string as a byte, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The byte value, if successful, null if parsing fails</returns>
        public static byte? TryParseByte(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            byte result;
            return byte.TryParse(value, out result) ? result : default(byte?);
        }

        /// <summary>
        /// Tries to parse a string as a char, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The char value, if successful, null if parsing fails</returns>
        public static char? TryParseChar(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            char result;
            return char.TryParse(value, out result) ? result : default(char?);
        }

        /// <summary>
        /// Tries to parse a string as a DateTime, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The DateTime value, if successful, null if parsing fails</returns>
        public static DateTime? TryParseDateTime(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            DateTime result;
            return DateTime.TryParse(value, out result) ? result : default(DateTime?);
        }

        /// <summary>
        /// Tries to parse a string as a DateTimeOffset, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The DateTimeOffset value, if successful, null if parsing fails</returns>
        public static DateTimeOffset? TryParseDateTimeOffset(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            DateTimeOffset result;
            return DateTimeOffset.TryParse(value, out result) ? result : default(DateTimeOffset?);
        }

        /// <summary>
        /// Tries to parse a string as a decimal, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The decimal value, if successful, null if parsing fails</returns>
        public static decimal? TryParseDecimal(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            decimal result;
            return decimal.TryParse(value, out result) ? result : default(decimal?);
        }

        /// <summary>
        /// Tries to parse a string as a double, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The decimal value, if successful, null if parsing fails</returns>
        public static double? TryParseDouble(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            double result;
            return double.TryParse(value, out result) ? result : default(double?);
        }

        /// <summary>
        /// Tries to parse a string as a short, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The short value, if successful, null if parsing fails</returns>
        public static short? TryParseShort(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            short result;
            return short.TryParse(value, out result) ? result : default(short?);
        }

        /// <summary>
        /// Tries to parse a string as a int, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The int value, if successful, null if parsing fails</returns>
        public static int? TryParseInt(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            int result;
            return int.TryParse(value, out result) ? result : default(int?);
        }

        /// <summary>
        /// Tries to parse a string as a long, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The long value, if successful, null if parsing fails</returns>
        public static long? TryParseLong(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            long result;
            return long.TryParse(value, out result) ? result : default(long?);
        }

        /// <summary>
        /// Tries to parse a string as a float, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The float value, if successful, null if parsing fails</returns>
        public static float? TryParseFloat(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            float result;
            return float.TryParse(value, out result) ? result : default(float?);
        }

        /// <summary>
        /// Tries to parse a string as a ushort, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The ushort value, if successful, null if parsing fails</returns>
        public static ushort? TryParseUnsignedShort(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            ushort result;
            return ushort.TryParse(value, out result) ? result : default(ushort?);
        }

        /// <summary>
        /// Tries to parse a string as a ulong, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The ulong value, if successful, null if parsing fails</returns>
        public static ulong? TryParseUnsignedLong(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            ulong result;
            return ulong.TryParse(value, out result) ? result : default(ulong?);
        }

        /// <summary>
        /// Tries to parse a string as a ipaddress, and return the 
        /// value if the parsing was successful.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The ipaddress value, if successful, null if parsing fails</returns>
        /// <remarks>
        /// I really have no idea why IPaddress.TryParse sollows the 
        /// same signature as the TryParse methods on value types.
        /// But, there you have it. To get a composable signature, I needed to 
        /// use the IPaddress, and use null to mean a parsing failure.
        /// </remarks>
        public static IPAddress TryParseIPAddress(this string value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "String to parse cannot be null");
            IPAddress result;
            return IPAddress.TryParse(value, out result) ? result : default(IPAddress);
        }

    }
}
